package me.caofeng.service;

import com.auth0.jwt.interfaces.DecodedJWT;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import me.caofeng.dao.UserMapper;
import me.caofeng.enums.ResponseCode;
import me.caofeng.enums.Role;
import me.caofeng.pojo.*;
import me.caofeng.service.api.INoticeService;
import me.caofeng.service.api.IUserService;
import me.caofeng.util.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.el.ELContext;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * Copyright © 2017曹峰. All rights reserved.
 *
 * @Prject: mall
 * @Package: me.caofeng.service
 * @Description:
 * @Author: 曹峰 blog.caofeng.me
 * @Date: 2017-06-15 19:59
 * @Version: V1.0
 */
@Service
@Transactional
public class UserService implements IUserService {
    private static Logger LOGGER = LogManager.getLogger(UserService.class);

    private Cache<String, Date> resetPasswordToken = CacheBuilder
            .newBuilder()
            .expireAfterWrite(10, TimeUnit.MINUTES)
            .build();

    private Cache<String, Map<Integer, SecurityQuestion>> questionCache = CacheBuilder
            .newBuilder()
            .expireAfterWrite(10, TimeUnit.MINUTES)
            .build();

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private INoticeService noticeService;

    public Response<User> register(User user) {

        Response isRegister = isRegister(user.getPhone());

        if (!isRegister.isSuccess()) {
            return isRegister;
        }

        user.setUid(UUIDUtil.generateUid());
        user.setPassword(MD5Util.Utf8Md5Encode(user.getPassword()));
        user.setRole(Role.MEMBER);
        int row = userMapper.addUser(user);
        if (row == 1) {
            user.setPassword("");
            return Response.response(ResponseCode.SUCCESS, "注册成功", user);
        } else {
            return Response.response(ResponseCode.ERROR, "注册失败 ", null);
        }

    }

    public Response isRegister(String phone) {
        if (!CheckUtil.isPhone(phone))
            return Response.response(ResponseCode.ILLEGAL_ARGUMENT, " 手机号错误", null);

        if (null != userMapper.isExits(phone))
            return Response.response(ResponseCode.ERROR, "账户已经存在", null);

        return Response.response(ResponseCode.SUCCESS, "可以注册", null);
    }

    public Response<User> login(String phone, String password) {

        User user = userMapper.getLoginInfo(phone);
        password = MD5Util.Utf8Md5Encode(password);

        if (null == user) {
            return Response.response(ResponseCode.ILLEGAL_ARGUMENT, "账号或密码错误", null);
        }

        if (password.equals(user.getPassword())) {
            user.setPhone(phone);
            user.setPassword("");
            return Response.response(ResponseCode.SUCCESS, "登录成功", user);
        } else {
            return Response.response(ResponseCode.ILLEGAL_ARGUMENT, "账号或密码错误", null);
        }

    }

    public Response getUserInfo(String uid) {
        if (null == uid) {
            return Response.response(ResponseCode.ILLEGAL_ARGUMENT, "用户不存在", null);
        }

        User user = userMapper.getUser(uid);
        if (null != user) {
            user.setUid(null);
            return Response.response(ResponseCode.SUCCESS, "获取用户信息成功", user);
        }

        return Response.response(ResponseCode.ERROR, "获取用户信息失败", null);
    }

    public Response addSecurityQuestions(QuestionForm questionForm, String userId) {

        int count = userMapper.countSecurityQuestion(userId);
        if (count == 3) {
            return Response.response(ResponseCode.ERROR, " 已经添加过安全问题，请尝试修改", null);
        }

        List<SecurityQuestion> questions = new ArrayList<SecurityQuestion>();
        List<SecurityQuestion> param = questionForm.getQuestions();

        if (param.size() != 3 || CheckUtil.isEmpty(userId)) {
            return Response.response(ResponseCode.ILLEGAL_ARGUMENT, "请输入问题和答案", null);
        }

        for (int i = 0; i < param.size(); i++) {
            SecurityQuestion securityQuestion = param.get(i);
            if (CheckUtil.isEmpty(securityQuestion.getQuestion()) || CheckUtil.isEmpty(securityQuestion.getAnswer())) {
                continue;
            }
            securityQuestion.setUserId(userId);
            questions.add(securityQuestion);
        }

        int row = userMapper.addSecurityQuestions(questions);

        if (questions.size() != row) {
            Response.response(ResponseCode.ERROR, " 添加安全问题失败", null);
        }

        return Response.response(ResponseCode.SUCCESS, " 添加安全问题成功 ", null);
    }

    public Response<List<SecurityQuestion>> getSecurityQuestions(String userId) {
        List<SecurityQuestion> questions = userMapper.getSecurityQuestions(userId);
        return Response.response(ResponseCode.SUCCESS, null, questions);
    }

    public Response<User> updateUserName(User user, String name) {

        int row = userMapper.updateUserInfo(name, null, null, user.getUid());

        if (1 != row) {
            return Response.response(ResponseCode.ERROR, "修改用户名失败,请重试", null);
        }
        return Response.response(ResponseCode.SUCCESS, "修改成功", null);
    }

    public Response updatePassword(String password, String userId) {
        LOGGER.debug("修改密码");

        password = MD5Util.Utf8Md5Encode(password);

        int row = userMapper.updateUserInfo(null,password,null,userId);

        if (row != 1){
            return Response.response(ResponseCode.ERROR, "修改密码失败", null);
        }

        return Response.response(ResponseCode.SUCCESS,"修改密码成功，请重新登录",null);
    }

    @Override
    public Response updatePhone( SmsCode smsCode,String userId) {
        Response<String> verifyPhone = noticeService.verifySmsCode(smsCode, null);

        if (!verifyPhone.isSuccess()) {
            return verifyPhone;
        }

        int row = 0;

        try {
            row = userMapper.updateUserInfo(null, null, smsCode.getPhone(), userId);
        } catch (Exception e) {
            LOGGER.error(e);
            return Response.response(ResponseCode.ERROR, "手机号已经被注册,请尝试申诉", null);
        }

        if (row == 1) {
            return Response.response(ResponseCode.SUCCESS, "手机号已更换", null);
        }

        return Response.response(ResponseCode.ERROR, "修改手机号失败", null);

    }

    public Response<SecurityQuestion> getSecurityQuestion(Integer id, String userId) {
        if (null == id || id <= 0 || CheckUtil.isEmpty(userId)) {
            return Response.response(ResponseCode.ILLEGAL_ARGUMENT, " 请求参数错误 ", null);
        }
        SecurityQuestion question = userMapper.getSecurityQuestion(id, userId);
        if (null != question) {
            return Response.response(ResponseCode.SUCCESS, null, question);
        }
        return Response.response(ResponseCode.ERROR, "查询失败", null);
    }

    public Response<SecurityQuestion> updateSecurityQuestion(Integer id, SecurityQuestion question, String userId) {
        if (null == id || id <= 0 || CheckUtil.isEmpty(userId) || null == question) {
            return Response.response(ResponseCode.ILLEGAL_ARGUMENT, " 请求参数错误 ", null);
        }

        if (CheckUtil.isEmpty(question.getQuestion()) || CheckUtil.isEmpty(question.getAnswer())) {
            return Response.response(ResponseCode.ILLEGAL_ARGUMENT, " 请求参数错误 ", null);
        }

        int row = userMapper.updateSecurityQuestion(id, userId, question);
        if (row == 1) {
            question.setId(id);
            return Response.response(ResponseCode.SUCCESS, null, question);
        }
        return Response.response(ResponseCode.ERROR, "修改安全问题失败", null);
    }

    @Override
    public Response resetPassword(String password, String confirm, String token) {

        if (!password.equals(confirm)) {
            return Response.response(ResponseCode.ILLEGAL_ARGUMENT, "密码不一致", null);
        }

        if (!CheckUtil.isPassword(password)) {
            return Response.response(ResponseCode.ILLEGAL_ARGUMENT, "密码要6位以上", null);
        }

        DecodedJWT jwt = JwtUtil.verifyToken(token);
        if (null == jwt) {
            return Response.response(ResponseCode.ILLEGAL_ARGUMENT, "验证码已失效", null);
        }

        List<String> audiences = jwt.getAudience();
        if (null == audiences || audiences.size() != 1) {
            return Response.response(ResponseCode.ILLEGAL_ARGUMENT, "验证码已失效", null);
        }

        String phone = jwt.getSubject();
        String userId = audiences.get(0);

        if (!CheckUtil.isPhone(phone)) {
            return Response.response(ResponseCode.ILLEGAL_ARGUMENT, "验证码错误", null);
        }


        Date issuedTime = resetPasswordToken.getIfPresent(userId);
        if (issuedTime != null && jwt.getIssuedAt().equals(issuedTime)) {
            //用户传来的token的签发时间和保存的签发时间一致，说明token已经被用过,
            return Response.response(ResponseCode.ILLEGAL_ARGUMENT, "验证码已失效", null);
        }

        password = MD5Util.Utf8Md5Encode(password);

        LOGGER.debug(" phone " + phone + " user id " + userId + " password " + password);
        int row = userMapper.resetPassword(phone, userId, password);
        if (row != 1) {
            return Response.response(ResponseCode.ERROR, "修改密码失败", null);
        }

        resetPasswordToken.put(userId, jwt.getIssuedAt());
        return Response.response(ResponseCode.SUCCESS, "修改密码成功", null);
    }

    @Override
    public Response<List<SecurityQuestion>> getQuestion(String phone) {
        if (!CheckUtil.isPhone(phone)) {
            return Response.response(ResponseCode.ILLEGAL_ARGUMENT, "用户不存在", null);
        }

        String userId = userMapper.isExits(phone);

        if (CheckUtil.isEmpty(userId)) {
            return Response.response(ResponseCode.ILLEGAL_ARGUMENT, "用户不存在", null);
        }

        Map<Integer, SecurityQuestion> questionMap = questionCache.getIfPresent(phone);
        List<SecurityQuestion> questions = null;

        if (null == questionMap) {
            questionMap = new HashMap<>();
            questions = userMapper.getSecurityQuestions(userId);
            for (SecurityQuestion question : questions) {
                SecurityQuestion cache = new SecurityQuestion();
                cache.setId(question.getId());
                cache.setQuestion(question.getQuestion());
                cache.setUserId(userId);
                cache.setAnswer(question.getAnswer());
                question.setAnswer(null);
                questionMap.put(question.getId(), cache);
            }
            questionCache.put(phone, questionMap);
        } else {
            questions = new ArrayList<>(questionMap.size());
            for (SecurityQuestion question : questionMap.values()) {
                SecurityQuestion response = new SecurityQuestion();
                response.setQuestion(question.getQuestion());
                response.setId(question.getId());
                questions.add(response);
            }
        }
        return Response.response(ResponseCode.SUCCESS, "OK", questions);
    }

    @Override
    public Response verifyQuestion(String answer, String phone, Integer id) {

        if (CheckUtil.isEmpty(answer) || !CheckUtil.isPhone(phone) || null == id) {
            LOGGER.info("格式错误");
            return Response.response(ResponseCode.ILLEGAL_ARGUMENT, "答案错误", null);
        }

        Map<Integer, SecurityQuestion> questionMap = questionCache.getIfPresent(phone);
        if (null == questionMap) {
            LOGGER.info("问题没有缓存");
            return Response.response(ResponseCode.ILLEGAL_ARGUMENT, "答案错误", null);
        }

        SecurityQuestion question = questionMap.get(id);
        LOGGER.info(question);

        if (null == question || !question.getAnswer().equals(answer)) {
            LOGGER.info("答案错误");
            questionCache.invalidate(phone);
            return Response.response(ResponseCode.ILLEGAL_ARGUMENT, "答案错误", null);
        }

        //答案正确，返回token
        String token = JwtUtil.createToken(phone, Constant.SMS_CODE_EXPIRE, question.getUserId());
        questionCache.invalidate(phone);
        return Response.response(ResponseCode.SUCCESS, "答案正确", token);
    }


}
